/*!
 * \file json_core.c
 *
 * \brief json 数据解析
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 1.0
 * \author geyh
 * \date 2017/03/02
 *
 */

#include <conntrack.h>
#include <frjson_checker.h>
#include <module.h>
#include <frct_comm.h>

#include <frreport_comm.h>
#include <frservice_comm.h>
#include "json_comm.h"
#include "json_data_analyze.h"
#include "config.h"

extern void *g_p_apm_context;

/*!
 * 判断当前数据链路是否是json协议的
 *
 * \param p_st_conn        (ct信息)
 * \param p_st_packet      (协议分析入力数据)
 *
 * \return 参照module.h中APM_L7_IS_的定义
 *
 */
int json_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = 0;
    int i_json_format = 0;

    if(p_st_conn == NULL || p_st_packet == NULL)
        return APM_L7_IS_NO;

    if(frjson_format_detect((unsigned char *)p_st_packet->p_payload, p_st_packet->ui_payload_len) == FR_YES)
    {
        if(frct_get_direct_known(p_st_conn) == FR_DIRECT_KNOWN)
        {
            if(p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
                frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
            else
                frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0);

            return APM_L7_IS_YES;
        }
        else
        {
            if((i_ret = frthrift_direction_detect(p_st_packet->p_payload)) != FR_DIRECT_UNKNOWN)
            {
                i_json_format = JSON_THRIFT;
                if(i_ret == FR_DIRECT_CLIENT2SRV)
                {
                    frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
                    frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, &i_json_format, sizeof(int));
                }
                else
                {
                    frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
                    frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, &i_json_format, sizeof(int));
                }

                return APM_L7_IS_YES;
            }
        }
    }

    //context 查询
    i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
    if (i_ret == FR_SUCC)
    {
        if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);

        return APM_L7_IS_YES;
    }

    i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
    if (i_ret == FR_SUCC)
    {
        if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);

        return APM_L7_IS_YES;
    }

    return APM_L7_IS_NO;
}

/*!
 * json私有数据创建
 *
 * \param void
 *
 * \return L7session_json_private
 *
 */
L7session_json_private* __json_private_create(void)
{
    L7session_json_private *p_st_private = (L7session_json_private *)frmalloc(sizeof(L7session_json_private));

    if(p_st_private == NULL)
        return NULL;

    memset(p_st_private, 0x00, sizeof(L7session_json_private));

    return p_st_private;

}

/*!
 * json私有数据销毁
 *
 * \param p_private_session     (私有数据)
 *
 * \return FR_SUCC
 *
 */
int json_session_destroy(void *p_private_session)
{
    L7session_json_private *p_st_private = (L7session_json_private *)p_private_session;

    if(p_st_private)
    {
        if(p_st_private->p_st_data)
            bytebuff_free(&p_st_private->p_st_data);

        if(p_st_private->p_report_comm)
            frreport_body_l7list_free(&p_st_private->p_report_comm);

        if(p_st_private->p_report_req)
            frreport_body_l7list_free(&p_st_private->p_report_req);

        if(p_st_private->pf_free && p_st_private->p_private_data)
            p_st_private->pf_free(&p_st_private->p_private_data);

        frfree(p_st_private);
    }

    return FR_SUCC;

}

/*!
 * json协议解析入口
 *
 * \param p_st_conn             (ct信息)
 * \param p_st_packet           (协议分析入力数据)
 * \param p_st_hash_report      (保存Frreport_data)
 *
 * \return 参照module.h中APM_L7_ANALYZE_的定义
 *
 */
int json_analyze(Conntrack *p_st_conn, Apm_packet *p_st_packet, Frhash_header *p_st_hash_report)
{
    L7_session *p_st_session = NULL;
    L7session_json_private *p_st_private = NULL;
    int i_ret = 0, i_is_out = 0;

    if(p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //fin syn  初始化数据
    if(p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN)
    {
        json_session_destroy(p_st_session->p_session_private);
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    //获取private
    if(p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = __json_private_create();
        if(p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;

        p_st_private = (L7session_json_private*)p_st_session->p_session_private;

        if(p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
        {
            i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, &p_st_private->i_json_format, sizeof(int), &i_is_out);
            if(i_ret == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;

        }
        else if(p_st_packet->i_direction == FR_DIRECT_SRV2CLIENT)
        {
            i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, &p_st_private->i_json_format, sizeof(int), &i_is_out);
            if(i_ret == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;
        }

    }

    p_st_private = (L7session_json_private*)p_st_session->p_session_private;

    if(p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        return frjson_req_analyze(p_st_packet, p_st_private, p_st_conn, p_st_hash_report);
    }
    else if(FR_DIRECT_SRV2CLIENT)
    {
        return frjson_resp_analyze(p_st_packet, p_st_private, p_st_conn, p_st_hash_report);
    }

    json_session_destroy(p_st_session->p_session_private);
    p_st_session->p_session_private = NULL;

    return APM_L7_ANALYZE_FAIL;

}
